'''
Created on Apr 16, 2013

@author: drelfi
'''

import os
import tempfile
import sys

from twisted.internet import utils, defer
from twisted.python import log

BASE_FOLDER = "c:\\temp\\cert\\"

# This function takes a real cert, and build a fake cert with the same
# CN and subjectAltName values, signed with "ca.crt" / "ca.key" in
# the current working direction
@defer.inlineCallbacks
def certMaker(cert, original_host):
    sbj = cert.get_subject()
    #components = sbj.get_components()
    
    if len(sbj.commonName) < 1:
        raise Exception('tip of subject is not commonName')

    hostname = sbj.commonName
    chash = sbj.hash()

    keyfile = '%s%s-key.pem' % (BASE_FOLDER, chash,)
    csrfile = '%s%s-csr.pem' % (BASE_FOLDER, chash,)
    certfile = '%s%s-crt.pem' % (BASE_FOLDER, chash,)

    try:
        # check for a cert already on-disk
        # with the same sha1 hash of binary blob
        os.stat(certfile)
    except:
        log.msg( "Making new fake cert - %s" % certfile )
    else:
        log.msg( "Using fake cert from disk - %s" % certfile )
        # file already exists on-disk
        # assume key is present too
        r = {
                'name': hostname,
                'cert': certfile,
                'key': keyfile,
                }
        defer.returnValue(r)


    # Is this sufficient? Maybe we want to copy whole DN?
    # Or read the 2nd & subsequent bits of the DN from our CA cert?
    subj = '/CN=%s/OU=FakeCA/O=My Fake CA' % (
            hostname,
            )

    # FIXME: key filenames by host/port combo, or maybe "real" cert hash?
    # FIXME: make the CA configurable?
    
    res = yield utils.getProcessOutputAndValue("C:\\OpenSSL\\bin\\openssl.exe",
        ('req','-newkey','rsa:1024','-nodes','-subj',subj,'-keyout',keyfile,'-out',csrfile),
        path=BASE_FOLDER
        )

    _, err, code = res
    if code!=0:
        raise Exception('error generating csr '+err)

    fd, tmpname = tempfile.mkstemp()
    try:
        ext = os.fdopen(fd, 'w')

        # write the subjectAltName extension into a temp .cnf file
        dns = []
        
        
        # Until we can get the subjectAltName from the cert, add the original cert name
        # TODO: FIXME! 
        dns.append("DNS:%s" % original_host)
        
        '''
        Insert real subjectAltName
        
        for ext in cert.get_extensions():
            if 'subjectAltName' == ext.get_short_name():
                for san in value.split(","):
                    if san.startswith('DNS'):
                        dns.append(san)
        '''
        if dns:
            print >>ext, "subjectAltName=" + ','.join(dns)

        # FIXME: copy other extensions? eku?
        ext.close()

        # process the .csr with our CA cert to generate a signed cert
        res = yield utils.getProcessOutputAndValue("C:\\OpenSSL\\bin\\openssl.exe",
            ('x509','-req','-days','365','-in',csrfile,'-CA','ca.crt','-CAkey','ca.key','-CAserial','file.srl','-extfile',tmpname,'-out',certfile),
            path=BASE_FOLDER
            )
    except:
        #log.msg("Exception caught while creating certfile: %s" % sys.exc_info() )
        print "Exception caught while creating certfile:", sys.exc_info()
        ext.close()
    finally:
        # remove temp file
        try:
            os.unlink(tmpname)
        except:
            pass

    _, err, code = res
    if code==0:
        r = {
                'name': hostname,
                'cert': certfile,
                'key': keyfile,
                }
        defer.returnValue(r)

    raise Exception('failed to generate cert '+err)

